﻿using Polenter.Serialization;
using Sunny.UI;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace SmartMotion.Core.Mgrs
{
    /// <summary>
    /// 变量管理
    /// </summary>
    public sealed class VarMgr
    {
        #region 属性单例模式

        private static readonly Lazy<VarMgr> Instance = new Lazy<VarMgr>(() => new VarMgr());

        private VarMgr()
        {
            Vars = new ConcurrentDictionary<string, ConcurrentDictionary<string, VarInfo>>();
        }

        public static VarMgr Ins { get; } = Instance.Value;

        #endregion 属性单例模式

        #region 属性

        /// <summary>
        /// 所有变量，大字典是分类，小字典存具体的变量
        /// </summary>
        public ConcurrentDictionary<string, ConcurrentDictionary<string, VarInfo>> Vars { get; }

        #endregion 属性

        #region 分组常量

        public static readonly string FlowVars = "FlowVars";
        public static readonly string MotionMgr = "MotionMgr";
        public static readonly string IoCards = "IoCards";
        public static readonly string IoMgr = "IoMgr";
        public static readonly string StationMgr = "StationMgr";
        public static readonly string Points = "Points";
        public static readonly string ProductPars = "ProductPars";
        public static readonly string SystemPars = "SystemPars";

        #endregion 分组常量

        #region 字典操作

        public void SaveDic(string dicName, string filePath)
        {
            if (Ins.Vars.ContainsKey(dicName))
            {
                var dic = new Dictionary<string, VarInfo>();
                //拿到并发字典，转换为普通字典保存
                CoucurrentDicToDic(Ins.Vars[dicName], dic);
                SharpSerializer serializer = new SharpSerializer();
                serializer.Serialize(dic, filePath);
                //Json.SaveExt<Dictionary<string, VarInfo>>(filePath, dic);
            }
        }
        public void ComboTreeLoadData(UIComboTreeView tv, List<string> varType)
        {
            tv.Nodes.Clear();
            foreach (string dic in Vars.Keys)
            {
                TreeNode dicNode = new TreeNode(dic);
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();
                foreach (var group in groups)
                {
                    TreeNode groupNode = new TreeNode(@group);

                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (!Vars[dic].ContainsKey(varInfo.Name)) break;
                        if (Vars[dic][varInfo.Name].Group == @group)
                        {
                            if (!string.IsNullOrEmpty(varInfo.Type))
                            {
                                if (varType.Contains(varInfo.Type))
                                {
                                    var node = groupNode.Nodes.Add(varInfo.Name);
                                    node.Tag = varInfo.VarID;
                                }
                            }
                        }
                    }

                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);
                    }
                }

                if (dicNode.Nodes.Count > 0)
                {
                    tv.Nodes.Add(dicNode);
                }
            }
        }

        public void ComboTreeLoadData<T>(UIComboTreeView tv)
        {
            tv.Nodes.Clear();
            foreach (string dic in Vars.Keys)
            {
                TreeNode dicNode = new TreeNode(dic);
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();
                foreach (var group in groups)
                {
                    TreeNode groupNode = new TreeNode(@group);

                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (!Vars[dic].ContainsKey(varInfo.Name)) continue;
                        if (Vars[dic][varInfo.Name].Group == @group)
                        {
                            if (!string.IsNullOrEmpty(varInfo.Type))
                            {
                                if (varInfo.Value is T)
                                {
                                    var node = groupNode.Nodes.Add(varInfo.Name);
                                    node.Tag = varInfo.VarID;
                                }
                            }
                        }
                    }

                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);
                    }
                }

                if (dicNode.Nodes.Count > 0)
                {
                    tv.Nodes.Add(dicNode);
                }
            }
        }


        public void LoadDic(string dicName, string filePath, bool iniValue = true)
        {
            //var dic = Json.LoadExt<Dictionary<string, VarInfo>>(filePath);

            var conDic = new ConcurrentDictionary<string, VarInfo>();
            try
            {
                SharpSerializer serializer = new SharpSerializer();
                //var dic = (Dictionary<string, VarInfo>)serializer.Deserialize(filePath);

                var dic = (Dictionary<string, VarInfo>)serializer.Deserialize(filePath);
                foreach (var varInfo in conDic.Values)
                {
                    if (iniValue)
                    {
                        varInfo.Value = varInfo.InitValue;
                    }
                }

                DicToCoucurrentDic(dic, conDic);
            }
            catch (Exception e)
            {
                UIMessageBox.ShowError($"加载变量集{dicName}时发生了异常\r{e.Message}\r{e.StackTrace}");
            }
            finally
            {
                if (Ins.Vars.ContainsKey(dicName))
                {
                    Ins.Vars[dicName] = conDic;
                }
                else
                {
                    Ins.Vars.TryAdd(dicName, conDic);
                }
            }
        }

        /// <summary>
        /// 并发字典转换为普通字典
        /// </summary>
        /// <param name="conDic"></param>
        /// <param name="dic"></param>
        private static void CoucurrentDicToDic(ConcurrentDictionary<string, VarInfo> conDic, Dictionary<string, VarInfo> dic)
        {
            dic.Clear();
            foreach (var varInfo in conDic)
            {
                dic.Add(varInfo.Key, varInfo.Value);
            }
        }

        /// <summary>
        /// 普通字典转换为并发字典
        /// </summary>
        /// <param name="dic"></param>
        /// <param name="conDic"></param>
        private static void DicToCoucurrentDic(Dictionary<string, VarInfo> dic, ConcurrentDictionary<string, VarInfo> conDic)
        {
            conDic.Clear();
            foreach (var varInfo in dic)
            {
                conDic.TryAdd(varInfo.Key, varInfo.Value);
            }
        }

        #endregion 字典操作

        #region 数据填充到下拉控件

        /// <summary>
        /// 传入一个类型和变量设置控件，安装类型过滤后填充数据到控件
        /// </summary>
        /// <param name="tv">变量设置控件</param>
        /// <param name="varType">变量类型</param>
        public void VarTreeLoadData(UITextBoxTree tv, string varType)
        {
            tv.ButtonTreeView.Nodes.Clear();//清空变量树
            foreach (var dic in Vars.Keys)
            {
                var dicNode = new TreeNode(dic);
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();

                foreach (var group in groups)
                {
                    var groupNode = new TreeNode(group);
                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (varInfo.Group == @group && varInfo.Type == varType)
                        {
                            var node = groupNode.Nodes.Add(varInfo.Name);//添加变量节点
                            node.Tag = varInfo.VarID;
                        }
                    }
                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);//添加分组到字典节点
                    }
                }
                if (dicNode.Nodes.Count > 0)
                {
                    tv.ButtonTreeView.Nodes.Add(dicNode);//添加字典节点
                }
            }

            tv.TextBoxTreeView.Nodes.Clear();//清空索引树
            foreach (var dic in Vars.Keys)
            {
                var dicNode = new TreeNode(dic);
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();

                foreach (var group in groups)
                {
                    var groupNode = new TreeNode(group);
                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (varInfo.Group == group)
                        {
                            if (varInfo.Type == typeof(int).FullName ||
                                varInfo.Type == typeof(uint).FullName ||
                                varInfo.Type == typeof(short).FullName ||
                                varInfo.Type == typeof(ushort).FullName)
                            {
                                var node = groupNode.Nodes.Add(varInfo.Name);//添加变量节点
                                node.Tag = varInfo.VarID;
                            }
                        }
                    }
                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);//添加分组到字典节点
                    }
                }
                if (dicNode.Nodes.Count > 0)
                {
                    tv.TextBoxTreeView.Nodes.Add(dicNode);//添加字典节点
                }
            }
        }

        /// <summary>
        /// 传入多个类型和变量设置控件，安装类型过滤后填充数据到控件
        /// </summary>
        /// <param name="tv">变量设置控件</param>
        /// <param name="varTypes">多个变量类型</param>
        public void VarTreeLoadData(UITextBoxTree tv, List<string> varTypes)
        {
            tv.ButtonTreeView.Nodes.Clear();//清空变量树
            foreach (var dic in Vars.Keys)
            {
                var dicNode = new TreeNode(dic);
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();

                foreach (var group in groups)
                {
                    var groupNode = new TreeNode(group);
                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (varInfo.Group == @group && varTypes.Contains(varInfo.Type))
                        {
                            var node = groupNode.Nodes.Add(varInfo.Name);//添加变量节点
                            node.Tag = varInfo.VarID;
                        }
                    }
                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);//添加分组到字典节点
                    }
                }
                if (dicNode.Nodes.Count > 0)
                {
                    tv.ButtonTreeView.Nodes.Add(dicNode);//添加字典节点
                }
            }

            tv.TextBoxTreeView.Nodes.Clear();//清空索引树
            foreach (var dic in Vars.Keys)
            {
                var dicNode = new TreeNode(dic);
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();

                foreach (var group in groups)
                {
                    var groupNode = new TreeNode(group);
                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (varInfo.Group == group)
                        {
                            if (varInfo.Type == typeof(int).FullName ||
                                varInfo.Type == typeof(uint).FullName ||
                                varInfo.Type == typeof(short).FullName ||
                                varInfo.Type == typeof(ushort).FullName)
                            {
                                var node = groupNode.Nodes.Add(varInfo.Name);//添加变量节点
                                node.Tag = varInfo.VarID;
                            }
                        }
                    }
                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);//添加分组到字典节点
                    }
                }
                if (dicNode.Nodes.Count > 0)
                {
                    tv.TextBoxTreeView.Nodes.Add(dicNode);//添加字典节点
                }
            }
        }

        public void ComboTreeLoadData(UIComboTreeView tv, string varType)
        {
            tv.Nodes.Clear();
            foreach (var dic in Vars.Keys)//遍历每个字典
            {
                var dicNode = new TreeNode(dic);//字典节点
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();//获得所有分组名称

                foreach (var group in groups)//遍历分组
                {
                    var groupNode = new TreeNode(group);//分组节点
                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (varInfo.Group == @group && varInfo.Type == varType)
                        {
                            var node = groupNode.Nodes.Add(varInfo.Name);//添加变量节点
                            node.Tag = varInfo.VarID;
                        }
                    }
                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);//添加分组到字典节点
                    }
                }
                if (dicNode.Nodes.Count > 0)
                {
                    tv.Nodes.Add(dicNode);//添加字典节点
                }
            }
        }

        #endregion 数据填充到下拉控件

        public VarInfo GetVarByName(string varName)
        {
            //非数组变量 字典.分组.变量名
            //数组变量 字典.分组.变量名[输入的索引]
            //数组变量 字典.分组.变量名[字典.分组.变量名]
            VarInfo varInfo = null;
            var keys = varName.Split(new[] { '.', '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
            if (keys.Length == 3)
            {
                if (Vars.ContainsKey(keys[0]))//字典存在
                {
                    if (Vars[keys[0]].ContainsKey(keys[2]))//变量名存在
                    {
                        varInfo = Vars[keys[0]][keys[2]];
                    }
                }
            }

            return varInfo;
        }

        public VarInfo GetVarByGuid(string objGuid)
        {
            //VarInfo varInfo1 = new VarInfo();
            //foreach (var dic in Vars)
            //{
            //    foreach (var varInfo in dic.Value)
            //    {
            //        if (varInfo.Value.VarID!=objGuid) continue;
            //        varInfo1 = varInfo.Value;
            //        return varInfo1;
            //    }
            //}
            //return varInfo1;
            return (from dic in Vars //foreach
                    from varinfo in dic.Value//foreach
                    where varinfo.Value.VarID == objGuid //if
                    select varinfo.Value).FirstOrDefault();
        }


        /// <summary>
        /// 获取所有已使用的类型
        /// </summary>
        /// <returns></returns>
        public List<string> GetAllTypes()
        {
            var typeList = new List<string>();
            foreach (var dicVar in Vars)
            {
                foreach (var varInfo in dicVar.Value)
                {
                    if (!typeList.Contains(varInfo.Value.Type))
                    {
                        typeList.Add(varInfo.Value.Type);
                    }
                }
            }
            return typeList;
        }

        public string GetConfigPath(string folder = "")
        {

            string allConfigPath = Environment.CurrentDirectory + "\\Config\\";
            if (!Directory.Exists(allConfigPath))
            {
                Directory.CreateDirectory(allConfigPath);
            }
            string cfgPath = allConfigPath;
            if (!string.IsNullOrEmpty(folder))
            {
                cfgPath += "\\" + folder;
            }

            if (!Directory.Exists(cfgPath))
            {
                Directory.CreateDirectory(cfgPath);
            }
            return cfgPath;
        }
    }
}